#include "Channel.hpp"
#include "Fiber.hpp"
#include <cassert>
#include <cerrno>
#include <cstring>
#include <mutex>
#include <unistd.h>

using namespace DBServer::coroutine;

Channel::Channel() { 
    if (pipe(chan) == -1) 
    {
        error("pipe error:%s\n", std::strerror(errno));
        throw;
    }
    //debug("pipe success[in(%d), out(%d)]\n", chan[0], chan[1]);
}

Channel::Channel(Channel && channel) {
    chan[0] = channel.chan[0];
    chan[1] = channel.chan[1];
    chan[0] = chan[1] = -1;
}

Channel& Channel::operator=(Channel&& channel) {
    chan[0] = channel.chan[0];
    chan[1] = channel.chan[1];
    chan[0] = chan[1] = -1;
    return *this;
}

Channel::~Channel() {
    if (chan[0] != -1)
        close(chan[0]);
    if (chan[1] != -1)
        close(chan[1]);
}

void Channel::pop() {
    std::unique_lock<std::mutex> lock(head_mtx);
    blocking_queue.pop();
}

void Channel::push() {
    std::unique_lock<std::mutex> lock(tail_mtx);
    blocking_queue.push(Fiber::GetThis());
}

template<>
void Channel::operator< <char*>(char *in) {
    std::unique_lock<std::mutex> lock(head_mtx);
    // 如果阻塞队列为空，则没有协程在这个channel上睡眠
    if (blocking_queue.empty()) {
        return;
    }

    int rt = write(chan[1], in, 1);
    if (rt < -1)
    {
        error("what():%s\n", strerror(errno));
        throw "";
    }

    // 唤醒一个协程
    auto hold_fiber = blocking_queue.front();
    hold_fiber->set_state(FiberState::READY);
    blocking_queue.pop();

}

template<>
void Channel::operator< <std::string>(std::string in) {
    std::unique_lock<std::mutex> lock(head_mtx);
    // 如果阻塞队列为空，则没有协程在这个channel上睡眠
    if (blocking_queue.empty()) {
        return;
    }

    if (in.length() == 0) 
        return;
    int rt = write(chan[1], in.c_str(), 1);
    if (rt < -1)
    {
        error("what():%s\n", strerror(errno));
        throw "";
    }
    // 唤醒一个协程
    auto hold_fiber = blocking_queue.front();
    hold_fiber->set_state(FiberState::READY);
    blocking_queue.pop();
}

template<>
void Channel::operator< <std::string&>(std::string& in) {
    if (in.length() == 0) 
        return;
    int rt = write(chan[1], in.c_str(), 1);   
    if (rt < -1)
    {
        error("what():%s\n", strerror(errno));
        throw "";
    }

    // 唤醒一个协程
    auto hold_fiber = blocking_queue.front();
    hold_fiber->set_state(FiberState::READY);
    blocking_queue.pop();
}

template<>
void Channel::operator< <std::string&&>(std::string&& in) {
    std::unique_lock<std::mutex> lock(head_mtx);
    // 如果阻塞队列为空，则没有协程在这个channel上睡眠
    if (blocking_queue.empty()) {
        return;
    }

    if (in.length() == 0) 
        return;
    int rt = write(chan[1], in.c_str(), 1);   
    if (rt < -1)
    {
        error("what():%s\n", strerror(errno));
        throw "";
    }
    // 唤醒一个协程
    auto hold_fiber = blocking_queue.front();
    hold_fiber->set_state(FiberState::READY);
    blocking_queue.pop();
}